\ ** ficl/softwords/softcore.fr
\ ** FICL soft extensions
\ ** John Sadler (john_sadler@alum.mit.edu)
\ ** September, 1998
\

\ ** Ficl USER variables
\ ** See words.c for primitive def'n of USER
\ #if FICL_WANT_USER
variable nUser  0 nUser ! 
: user   \ name ( -- )  
    nUser dup @ user 1 swap +! ; 

\ #endif

\ ** ficl extras
\ EMPTY cleans the parameter stack
: empty   ( xn..x1 -- ) depth 0 ?do drop loop ;
\ CELL- undoes CELL+
: cell-   ( addr -- addr )  [ 1 cells ] literal -  ;
: -rot   ( a b c -- c a b )  2 -roll ;

\ ** CORE 
: abs   ( x -- x )
    dup 0< if negate endif ;
decimal 32 constant bl

: space   ( -- )     bl emit ;

: spaces  ( n -- )   0 ?do space loop ;

: abort"  
    state @ if
        postpone if
        postpone ."
        postpone cr
        -2
        postpone literal
        postpone throw
        postpone endif
    else
	    [char] " parse
        rot if
            type
            cr
            -2 throw
        else
            2drop
        endif
    endif
; immediate


\ ** CORE EXT
0  constant false 
false invert constant true 
: <>   = 0= ; 
: 0<>  0= 0= ; 
: compile,  , ; 
: convert   char+ 65535 >number drop ;  \ cribbed from DPANS A.6.2.0970
: erase   ( addr u -- )    0 fill ; 
variable span
: expect  ( c-addr u1 -- ) accept span ! ;
\ see marker.fr for MARKER implementation
: nip     ( y x -- x )     swap drop ; 
: tuck    ( y x -- x y x)  swap over ; 
: within  ( test low high -- flag )   over - >r - r>  u<  ;

: u.r ( n +n -- )
  swap 0 <# #s #>
  rot over - dup 0< if
    drop else spaces
  then
  type space ;

\ ** LOCAL EXT word set
\ #if FICL_WANT_LOCALS
: locals|  ( name...name | -- )
    begin
        bl word   count
        dup 0= abort" where's the delimiter??"
        over c@
        [char] | - over 1- or
    while
        (local)
    repeat 2drop   0 0 (local)
; immediate

: local  ( name -- )  bl word count (local) ;  immediate

: 2local  ( name -- ) bl word count (2local) ; immediate

: end-locals  ( -- )  0 0 (local) ;  immediate

\ #endif

\ ** TOOLS word set...
: ?     ( addr -- )  @ . ;

Variable /dump

: i' ( R:w R:w2 -- R:w R:w2 w )
  r> r> r> dup >r swap >r swap >r ;

: .4 ( addr -- addr' )
    4 0 DO  -1 /dump +!  /dump @ 0<
        IF 3 spaces  ELSE  dup c@ 0 <# # # #> type space  THEN
    char+ LOOP ;

: .chars ( addr -- )
    /dump @ over + swap
    ?DO I c@ dup 127 bl within
        IF  drop [char] .  THEN  emit
    LOOP ;

: .line ( addr -- )
  dup .4 space .4 ." - " .4 space .4 drop  16 /dump +!  space .chars ;

: dump  ( addr u -- ) \ tools dump
    cr base @ >r hex        \ save base on return stack
    0 ?DO  I' I - 16 min /dump !
        dup 8 u.r ." : " dup .line cr 16 +
        16 +LOOP
    drop r> base ! ;

\ ** SEARCH+EXT words and ficl helpers
\ BRAND-WORDLIST is a helper for ficl-named-wordlist. Usage idiom:
\   wordlist dup create , brand-wordlist
\ gets the name of the word made by create and applies it to the wordlist...
: brand-wordlist  ( wid -- )   last-word >name drop wid-set-name ;

: ficl-named-wordlist  \ ( hash-size name -- ) run: ( -- wid )
    ficl-wordlist dup create , brand-wordlist does> @ ;

: wordlist   ( -- )  
    1 ficl-wordlist ;

\ FICL-SET-CURRENT sets the compile wordlist and pushes the previous value
: ficl-set-current   ( wid -- old-wid )  
    get-current swap set-current ; 

\ DO_VOCABULARY handles the DOES> part of a VOCABULARY
\ When executed, new voc replaces top of search stack
: do-vocabulary   ( -- ) 
    does>  @ search> drop >search ;

: ficl-vocabulary   ( nBuckets name -- )  
    ficl-named-wordlist do-vocabulary ; 

: vocabulary   ( name -- )  
    1 ficl-vocabulary ; 

\ PREVIOUS drops the search order stack
: previous  ( --  )  search> drop ; 

\ HIDDEN vocabulary is a place to keep helper words from cluttering the namespace
\ USAGE:
\ hide
\ <definitions to hide>
\ set-current
\ <words that use hidden defs>
\ previous ( pop HIDDEN off the search order )

1 ficl-named-wordlist hidden
: hide     hidden dup >search ficl-set-current ;

\ ALSO dups the search stack...
: also   ( -- )  
    search> dup >search >search ; 

\ FORTH drops the top of the search stack and pushes FORTH-WORDLIST
: forth   ( -- )  
    search> drop  
    forth-wordlist >search ; 

\ ONLY sets the search order to a default state
: only   ( -- )  
    -1 set-order ; 

\ ORDER displays the compile wid and the search order list
hide
: list-wid ( wid -- )   
    dup wid-get-name   ( wid c-addr u )
    ?dup if 
        type drop 
    else 
        drop ." (unnamed wid) " x.
    endif cr 
; 
set-current   \ stop hiding words

: order   ( -- )  
    ." Search:" cr
    get-order  0 ?do 3 spaces list-wid loop cr 
   ." Compile: " get-current list-wid cr  
; 

: debug  ' debug-xt ; immediate
: on-step   ." S: " .s cr ;


\ Submitted by lch.
: strdup ( c-addr length -- c-addr2 length2 ior )
	0 locals| addr2 length c-addr | end-locals
	length 1 + allocate
	0= if
		to addr2
		c-addr addr2 length move
		addr2 length 0
	else
		0  -1
	endif
	;

: strcat ( 2:a 2:b -- 2:new-a )
	0 locals|  b-length b-u b-addr a-u a-addr | end-locals
	b-u  to b-length
	b-addr a-addr a-u + b-length  move
	a-addr a-u b-length +
	;

: strcpy ( 2:a 2:b -- 2:new-a )
	locals| b-u b-addr a-u a-addr | end-locals
	a-addr 0  b-addr b-u  strcat
	;

: xemit ( xchar -- )
 	dup 0x80 u< if emit exit then \ special case ASCII
 	0 swap 0x3F
 	begin 2dup u> while
 		2/ >r dup 0x3F and 0x80 or swap 6 rshift r>
 	repeat 0x7F xor 2* or
 	begin dup 0x80 u< 0= while emit repeat drop
 	;

previous   \ lose hidden words from search order

\ ** E N D   S O F T C O R E . F R

